/*!
\copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\defgroup   hfp_profile
\brief      The events sent from the hfp profile using the Event Bus
*/

#include "hfp_profile_event_send.h"
#include "hfp_profile_channel_event_spec.h"
#include "hfp_profile_instance.h"
#include "hfp_profile_states.h"

#include "event_bus_publish.h"

#include <logging.h>

static void hfpProfile_EventBusSend(hfp_profile_event_t event, void * data, uint16 data_size)
{
    EventBus_Publish(EVENT_BUS_CHANNEL_HFP_PROFILE, event, data, data_size);
}

static hfp_profile_event_call_setup_t hfpProfile_EventSendGetCallSetupState(hfp_call_state call_state)
{
    hfpState hfp_state = hfpProfile_GetStateFromCallState(call_state);
    hfp_profile_event_call_setup_t call_setup = hfp_profile_event_call_setup_none;
    
    if (HfpProfile_StateHasIncomingCall(hfp_state))
    {
        call_setup = hfp_profile_event_call_setup_incoming;
    }   
    else if (HfpProfile_StateHasOutgoingCall(hfp_state))
    {
        call_setup = hfp_profile_event_call_setup_outgoing;
    }
    /* Currently alerting is not stored */
    
    return call_setup;
}

static hfp_profile_event_call_t hfpProfile_EventSendGetCallState(hfp_call_state call_state)
{
    hfpState hfp_state = hfpProfile_GetStateFromCallState(call_state);
    hfp_profile_event_call_t call = hfp_profile_event_call_inactive;
    
    if (HfpProfile_StateHasActiveCall(hfp_state))
    {
        call = hfp_profile_event_call_active;
    }
    
    return call;
}

static hfp_profile_event_call_held_t hfpProfile_EventSendGetCallHeldState(hfp_call_state call_state)
{
    hfpState hfp_state = hfpProfile_GetStateFromCallState(call_state);
    hfp_profile_event_call_held_t call_held = hfp_profile_event_call_held_inactive;
    
    if (HfpProfile_StateHasHeldCall(hfp_state))
    {
        if (HfpProfile_StateHasActiveCall(hfp_state))
        {
            call_held = hfp_profile_event_call_held_active;
        }
        else
        {
            call_held = hfp_profile_event_call_held_no_active;
        }
    }
    
    return call_held;
}

static uint8 hfpProfile_EventSendGetVolume(hfpInstanceTaskData *instance)
{
    voice_source_t source = HfpProfileInstance_GetVoiceSourceForInstance(instance);
    uint8 volume = 0;
    
    if ((source > voice_source_none) && (source < max_voice_sources))
    {
        volume_t voice_vol = VoiceSources_GetVolume(source);
        volume = voice_vol.value;
    }
    
    return volume;
}

void HfpProfile_EventSendHfpConnected(hfpInstanceTaskData *instance, uint32 hfg_supported_features)
{
    DEBUG_LOG("HfpProfile_EventSendHfpConnected");
    
    hfp_profile_event_connected_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.supported_features = hfg_supported_features;
    event.call_setup = hfpProfile_EventSendGetCallSetupState(instance->bitfields.call_state);
    event.call = hfpProfile_EventSendGetCallState(instance->bitfields.call_state);
    event.call_held = hfpProfile_EventSendGetCallHeldState(instance->bitfields.call_state);
    event.volume = hfpProfile_EventSendGetVolume(instance);
    hfpProfile_EventBusSend(hfp_profile_event_connected, &event, sizeof(hfp_profile_event_connected_t));
}

void HfpProfile_EventSendHfpDisconnected(hfpInstanceTaskData *instance)
{
    DEBUG_LOG("HfpProfile_EventSendHfpDisconnected");
    
    hfp_profile_event_disconnected_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.reason = hfp_profile_disconnect_error;
    
    switch (instance->bitfields.disconnect_reason)
    {
        case APP_HFP_DISCONNECT_NORMAL:
            {
                event.reason = hfp_profile_disconnect_normal;
            }
            break;
        case APP_HFP_DISCONNECT_LINKLOSS:
            {
                event.reason = hfp_profile_disconnect_linkloss;
            }
            break;
        default:
            break;
    }
            
    hfpProfile_EventBusSend(hfp_profile_event_disconnected, &event, sizeof(hfp_profile_event_disconnected_t));
}

void HfpProfile_EventSendHfpAudioConnected(hfpInstanceTaskData *instance)
{
    DEBUG_LOG("HfpProfile_EventSendHfpAudioConnected");
    
    hfp_profile_event_audio_connected_t event = {0};
    event.addr = instance->ag_bd_addr;
    hfpProfile_EventBusSend(hfp_profile_event_audio_connected, &event, sizeof(hfp_profile_event_audio_connected_t));
}

void HfpProfile_EventSendHfpAudioDisconnected(hfpInstanceTaskData *instance, uint16 reason)
{
    DEBUG_LOG("HfpProfile_EventSendHfpAudioDisconnected");
    
    hfp_profile_event_audio_disconnected_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.reason = reason;
    hfpProfile_EventBusSend(hfp_profile_event_audio_disconnected, &event, sizeof(hfp_profile_event_audio_disconnected_t));
}

void HfpProfile_EventSendHfpCallUpdate(hfpInstanceTaskData *instance, hfp_call_state previous_call_state)
{
    DEBUG_LOG("HfpProfile_EventSendHfpCallUpdate");
    
    hfp_profile_event_call_setup_t previous_call_setup = hfpProfile_EventSendGetCallSetupState(previous_call_state);
    hfp_profile_event_call_setup_t new_call_setup = hfpProfile_EventSendGetCallSetupState(instance->bitfields.call_state);
    
    hfp_profile_event_call_t previous_call = hfpProfile_EventSendGetCallState(previous_call_state);
    hfp_profile_event_call_t new_call = hfpProfile_EventSendGetCallState(instance->bitfields.call_state);
    
    hfp_profile_event_call_held_t previous_call_held = hfpProfile_EventSendGetCallHeldState(previous_call_state);
    hfp_profile_event_call_held_t new_call_held = hfpProfile_EventSendGetCallHeldState(instance->bitfields.call_state);
    
    if (previous_call_setup != new_call_setup)
    {
        hfp_profile_event_callsetup_ind_t event = {0};
        event.addr = instance->ag_bd_addr;
        event.call_setup = new_call_setup;
        hfpProfile_EventBusSend(hfp_profile_event_callsetup_ind, &event, sizeof(hfp_profile_event_callsetup_ind_t));
    }
    
    if (previous_call != new_call)
    {
        hfp_profile_event_call_ind_t event = {0};
        event.addr = instance->ag_bd_addr;
        event.call = new_call;
        hfpProfile_EventBusSend(hfp_profile_event_call_ind, &event, sizeof(hfp_profile_event_call_ind_t));
    }
    
    if (previous_call_held != new_call_held)
    {
        hfp_profile_event_callheld_ind_t event = {0};
        event.addr = instance->ag_bd_addr;
        event.call_held = new_call_held;
        hfpProfile_EventBusSend(hfp_profile_event_callheld_ind, &event, sizeof(hfp_profile_event_callheld_ind_t));
    }
}

void HfpProfile_EventSendHfpRingInd(hfpInstanceTaskData *instance)
{
    DEBUG_LOG("HfpProfile_EventSendHfpRingInd");
    
    hfp_profile_event_ring_ind_t event = {0};
    event.addr = instance->ag_bd_addr;
    hfpProfile_EventBusSend(hfp_profile_event_ring_ind, &event, sizeof(hfp_profile_event_ring_ind_t));
}

void HfpProfile_EventSendSpeakerGainInd(hfpInstanceTaskData *instance, uint8 gain)
{
    DEBUG_LOG("HfpProfile_EventSendSpeakerGainInd");
    
    hfp_profile_event_speaker_gain_ind_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.gain = gain;
    hfpProfile_EventBusSend(hfp_profile_event_speaker_gain_ind, &event, sizeof(hfp_profile_event_speaker_gain_ind_t));
}

void HfpProfile_EventSendMicGainInd(hfpInstanceTaskData *instance, uint8 gain)
{
    DEBUG_LOG("HfpProfile_EventSendMicGainInd");
    
    hfp_profile_event_mic_gain_ind_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.gain = gain;
    hfpProfile_EventBusSend(hfp_profile_event_mic_gain_ind, &event, sizeof(hfp_profile_event_mic_gain_ind_t));
}

void HfpProfile_EventSendHfpInbandRingInd(hfpInstanceTaskData *instance)
{
    DEBUG_LOG("HfpProfile_EventSendHfpInbandRingInd");
    
    hfp_profile_event_inband_ring_ind_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.enable = instance->bitfields.in_band_ring ? TRUE : FALSE;
    hfpProfile_EventBusSend(hfp_profile_event_inband_ring_ind, &event, sizeof(hfp_profile_event_inband_ring_ind_t));
}

void HfpProfile_EventSendHfpVoiceRecognitionInd(hfpInstanceTaskData *instance)
{
    DEBUG_LOG("HfpProfile_EventSendHfpVoiceRecognitionInd");
    
    hfp_profile_event_voice_recognition_ind_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.enable = instance->bitfields.voice_recognition_active ? TRUE : FALSE;
    hfpProfile_EventBusSend(hfp_profile_event_voice_recognition_ind, &event, sizeof(hfp_profile_event_voice_recognition_ind_t));
}

void HfpProfile_EventSendHfpAtCommandComplete(hfpInstanceTaskData *instance, bool success)
{
    DEBUG_LOG("HfpProfile_EventSendHfpAtCommandComplete");
    
    hfp_profile_event_at_command_complete_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.success = success;
    hfpProfile_EventBusSend(hfp_profile_event_at_command_complete, &event, sizeof(hfp_profile_event_at_command_complete_t));
}

void HfpProfile_EventSendHfpUnknownAtCommandReceived(hfpInstanceTaskData *instance, uint8* data, uint16 data_size)
{
    DEBUG_LOG("HfpProfile_EventSendHfpUnknownAtCommandReceived");

    hfp_profile_event_unknown_at_command_received_t event = {0};
    event.addr = instance->ag_bd_addr;
    event.data_size = data_size;
    event.data = data;

    hfpProfile_EventBusSend(hfp_profile_event_unknown_at_command_received, &event, sizeof(hfp_profile_event_unknown_at_command_received_t));
}
